package db

import (
    "fmt"
    "reflect"
    "strconv"
)

type StrTo string

// set string
func (f *StrTo) Set(v string) {
    if v != "" {
        *f = StrTo(v)
    } else {
        f.Clear()
    }
}

// clean string
func (f *StrTo) Clear() {
    *f = StrTo(0x1E)
}

// check string exist
func (f StrTo) Exist() bool {
    return string(f) != string(0x1E)
}

// string to bool
func (f StrTo) Bool() (bool, error) {
    return strconv.ParseBool(f.String())
}

// string to float32
func (f StrTo) Float32() (float32, error) {
    v, err := strconv.ParseFloat(f.String(), 32)
    return float32(v), err
}

// string to float64
func (f StrTo) Float64() (float64, error) {
    return strconv.ParseFloat(f.String(), 64)
}

// string to int
func (f StrTo) Int() (int, error) {
    v, err := strconv.ParseInt(f.String(), 10, 32)
    return int(v), err
}

// string to int8
func (f StrTo) Int8() (int8, error) {
    v, err := strconv.ParseInt(f.String(), 10, 8)
    return int8(v), err
}

// string to int16
func (f StrTo) Int16() (int16, error) {
    v, err := strconv.ParseInt(f.String(), 10, 16)
    return int16(v), err
}

// string to int32
func (f StrTo) Int32() (int32, error) {
    v, err := strconv.ParseInt(f.String(), 10, 32)
    return int32(v), err
}

// string to int64
func (f StrTo) Int64() (int64, error) {
    v, err := strconv.ParseInt(f.String(), 10, 64)
    return int64(v), err
}

// string to uint
func (f StrTo) Uint() (uint, error) {
    v, err := strconv.ParseUint(f.String(), 10, 32)
    return uint(v), err
}

// string to uint8
func (f StrTo) Uint8() (uint8, error) {
    v, err := strconv.ParseUint(f.String(), 10, 8)
    return uint8(v), err
}

// string to uint16
func (f StrTo) Uint16() (uint16, error) {
    v, err := strconv.ParseUint(f.String(), 10, 16)
    return uint16(v), err
}

// string to uint31
func (f StrTo) Uint32() (uint32, error) {
    v, err := strconv.ParseUint(f.String(), 10, 32)
    return uint32(v), err
}

// string to uint64
func (f StrTo) Uint64() (uint64, error) {
    v, err := strconv.ParseUint(f.String(), 10, 64)
    return uint64(v), err
}

// string to string
func (f StrTo) String() string {
    if f.Exist() {
        return string(f)
    }
    return ""
}

// interface to string
func ToStr(value interface{}, args ...int) (s string) {
    switch v := value.(type) {
        case bool:
        s = strconv.FormatBool(v)
        case float32:
        s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
        case float64:
        s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
        case int:
        s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
        case int8:
        s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
        case int16:
        s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
        case int32:
        s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
        case int64:
        s = strconv.FormatInt(v, argInt(args).Get(0, 10))
        case uint:
        s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
        case uint8:
        s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
        case uint16:
        s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
        case uint32:
        s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
        case uint64:
        s = strconv.FormatUint(v, argInt(args).Get(0, 10))
        case string:
        s = v
        case []byte:
        s = string(v)
        default:
        s = fmt.Sprintf("%v", v)
    }
    return s
}

type argString []string

// get string by index from string slice
func (a argString) Get(i int, args ...string) (r string) {
    if i >= 0 && i < len(a) {
        r = a[i]
    } else if len(args) > 0 {
        r = args[0]
    }
    return
}

type argInt []int

// get int by index from int slice
func (a argInt) Get(i int, args ...int) (r int) {
    if i >= 0 && i < len(a) {
        r = a[i]
    }
    if len(args) > 0 {
        r = args[0]
    }
    return
}

type argAny []interface{}

// get interface by index from interface slice
func (a argAny) Get(i int, args ...interface{}) (r interface{}) {
    if i >= 0 && i < len(a) {
        r = a[i]
    }
    if len(args) > 0 {
        r = args[0]
    }
    return
}

// get pointer indirect type
func indirectType(v reflect.Type) reflect.Type {
    switch v.Kind() {
        case reflect.Ptr:
        return indirectType(v.Elem())
        default:
        return v
    }
}
